package com.imachen.basic.service.impl;

import com.imachen.basic.constent.VerifyCodeConstant;
import com.imachen.basic.dto.SmsCodeDto;
import com.imachen.basic.exception.BusinessException;
import com.imachen.basic.service.IVerifyService;
import com.imachen.basic.utils.StrUtils;
import com.imachen.basic.utils.VerifyCodeUtils;
import com.imachen.user.domain.User;
import com.imachen.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.concurrent.TimeUnit;
@Service
public class IVerifyServiceImpl implements IVerifyService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private JavaMailSender javaMailSender;

    @Override
    public String image(String key) {
        //生成图形验证码
        String code = StrUtils.getComplexRandomString(4);
        // 保存到redis
        redisTemplate.opsForValue().set(key,code,5, TimeUnit.MINUTES);
        // 使用工具类生成图形验证码编码之后的base64字符串
        String base64Str = VerifyCodeUtils.verifyCode(110, 40, code);

        return base64Str;
    }

    @Override
    public void smsCode(SmsCodeDto smsCodeDto) {
        //一：校验 - 空值校验
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        String imageCode = smsCodeDto.getImageCode();
        String phone = smsCodeDto.getPhone();
        if(StringUtils.isEmpty(phone)){
            throw new BusinessException("手机号不能为空！");
        }
        if(StringUtils.isEmpty(imageCode)){
            throw new BusinessException("图形验证码不能为空！");
        }
        if(StringUtils.isEmpty(imageCodeKey)){
            throw new BusinessException("请刷新页面重新获取图片验证码");
        }
        //二：校验 - 校验图形验证码是否过期 和 是否正确
        Object o = redisTemplate.opsForValue().get(imageCodeKey);
        if (o==null){
            throw new BusinessException("图形验证码过期,请重新获取！");
        }
        if (!o.toString().equalsIgnoreCase(imageCode)){
            throw new BusinessException("图形验证码错误！");
        }
        //三：校验 - 手机号码是否注册过【如果查询t_logininfo还需要传一个type=1】
        User user = userMapper.findOneByPhone(phone);
        if(user!=null){
            throw new BusinessException("手机号码已经注册，请直接登录");
        }
        //四：获取手机验证码，判断是否过期 【register:phone - code:时间戳】
        Object codeObj = redisTemplate.opsForValue().get("register:" + phone);
        String smsCode = null;
        //1.过期了或者没有，通过工具类生成
        if(codeObj==null){
            smsCode = StrUtils.getRandomString(4);
        }else{
            //2.没有过期 - 还有用 【3分钟】
            //2.1.判断是否过重发时间 - 利用时间戳相减><60*1000
            long oldTime = Long.parseLong(codeObj.toString().split(":")[1]);
            //2.2.如果没有过重发时间 - 违规操作 - 抛异常
            if((System.currentTimeMillis()-oldTime)<60*1000){//没过重发时间
                throw new BusinessException("请勿频繁操作，稍后重试!!!");
            }
            //2.2.如果过了重发时间【1分钟】 - 使用上面的验证码
            smsCode = codeObj.toString().split(":")[0];
        }

        //3.保存到redis - 重新设置3分钟过期
        redisTemplate.opsForValue().set("register:"+phone,smsCode+":"+System.currentTimeMillis(),3,TimeUnit.MINUTES);

        //4.调用工具类发送短信 - sout作弊
//        SmsUtils.sendSms(phone,"你的验证码为："+smsCode+",请在三分钟内使用!!!");
        System.out.println("你的验证码为："+smsCode+",请在三分钟内使用!!!");

    }

    // 邮箱验证码
    @Override
    public void emailCode(SmsCodeDto smsCodeDto) throws MessagingException {
        //一：校验 - 空值校验
        String email = smsCodeDto.getEmail();
        if(StringUtils.isEmpty(email)){
            throw new BusinessException("邮箱不能为空！");
        }
        //三：校验 - 手机号码是否注册过【如果查询t_logininfo还需要传一个type=1】
        User user = userMapper.findOneByEmail(email);
        if(user!=null){
            throw new BusinessException("该邮箱已经注册，请直接登录");
        }
        //四：获取手机验证码，判断是否过期 【register:phone - code:时间戳】
        Object codeObj = redisTemplate.opsForValue().get("register:" + email);
        String emailCode = null;
        //1.过期了或者没有，通过工具类生成
        if(codeObj==null){
            emailCode = StrUtils.getRandomString(4);
        }else{
            //2.没有过期 - 还有用 【3分钟】
            //2.1.判断是否过重发时间 - 利用时间戳相减><60*1000
            long oldTime = Long.parseLong(codeObj.toString().split(":")[1]);
            //2.2.如果没有过重发时间 - 违规操作 - 抛异常
            if((System.currentTimeMillis()-oldTime)<60*1000){//没过重发时间
                throw new BusinessException("请勿频繁操作，稍后重试!!!");
            }
            //2.2.如果过了重发时间【1分钟】 - 使用上面的验证码
            emailCode = codeObj.toString().split(":")[0];
        }
        //3.保存到redis - 重新设置3分钟过期
        redisTemplate.opsForValue().set("register:"+email,emailCode+":"+System.currentTimeMillis(),3,TimeUnit.MINUTES);
        //4.调用工具类发送短信 - sout作弊
//        SmsUtils.sendSms(phone,"你的验证码为："+smsCode+",请在三分钟内使用!!!");
        System.out.println("你的验证码为："+emailCode+",请在三分钟内使用!!!");
        //五：发送验证码邮件
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
        helper.setFrom("lihonggang0612@qq.com");
        helper.setTo(email);
        helper.setSubject("用户邮箱注册邮件");
        helper.setText("<h1>用户邮箱注册验证码</h1><h2>您的验证码为："+emailCode+"</h2>",true);
        javaMailSender.send(message);
    }

    @Override
    public void binderSmsCode(SmsCodeDto smsCodeDto) {
        String phone = smsCodeDto.getPhone();
        //1.校验
        //a.非空校验 - 3个
        if(StringUtils.isEmpty(phone)){
            throw new BusinessException("手机号码不能为空");
        }
        //2.生成手机验证码
        //redis保存手机验证码：register:18856566636 - 9527:156336655555
        //a.从redis中获取手机验证码 - 进行判断
        Object smsObj = redisTemplate.opsForValue().get(VerifyCodeConstant.BINDER_CODE_PREFIX + phone); //9527:156336655555
        String smsCode = null;
        if(smsObj == null){
            //a1.如果没有 = 第一次获取或手机验证码过期 -> 重新调用StrUtils创建新的手机验证码
            smsCode = StrUtils.getRandomString(6);
        }else{
            //a2.如果有 = 手机验证码过期没有过期 -> 判断重发时间【时间戳相减与1分钟】
            long nowTime = System.currentTimeMillis();
            String oldTimeTemp = smsObj.toString().split(":")[1];
            long oldTime = Long.parseLong(oldTimeTemp);
            if((nowTime-oldTime)<1*60*1000){//重复发送短信验证码
                //a21.如果没有过重发时间 -> 抛业务异常【操作过于频繁，请稍后再试】
                throw new BusinessException("操作过于频繁，请稍后再试");
            }else{
                //a22.如果过了重发时间 -> 就使用以前的验证码
                smsCode = smsObj.toString().split(":")[0];
            }
        }
        //3.手机验证码保存到redis - 要不要刷新过期时间？[保存到redis要不要再次设置3分钟有效]
        redisTemplate.opsForValue().set(VerifyCodeConstant.BINDER_CODE_PREFIX+phone,
                smsCode+":"+System.currentTimeMillis(),3,TimeUnit.MINUTES);
        //4.调用工具类发送短信
        //SmsUtils.sendSms(phone,"你的验证码是：" + smsCode+",请在3分钟内使用!!!");
        System.out.println("你的验证码是：" + smsCode+",请在3分钟内使用!!!");
    }
}
